# @Time : 2021/4/15 10:05
# @Author : Fioman 
# @Phone : 13149920693
import threading

import gevent

from db_tools.db_handler import DbHandler
from eap_mysql.mysql_handler import MysqlHandler
from tools.common_tools import stop_thread
from tools.hd_logger import HdLogger
from tools.send_to_ui_tools import send_cbj_zmc_tool_state_to_ui

"""
裁切机控制器的类,主要用来处理裁切机工具那一个栏目的工具的使用状态
"""
sqlHdr = MysqlHandler()


class CbjTool(object):
    def __init__(self, cbjZmc):
        self.cbjZmc = cbjZmc
        self.logger = HdLogger()
        self.db = DbHandler()
        self.cbj_tool_prepare_init()  # 裁切机的参数初始化加载到内存

    def cbj_tool_prepare_init(self):
        """
        裁切机额一些参数加载到内存中
        :return:
        """
        self.sendCbjPosFlag = False  # 是否发送裁切机的坐标到前端
        self.reload_knfie_cut_params()

    def reload_knfie_cut_params(self):
        """
        重新加载刀切割的时候的一些参数
        :return:
        """
        res, knifeCutParams = self.db.get_knife_cut_params()
        if res != "ok":
            errorInfo = knifeCutParams
            print(errorInfo)
            self.logger.debug(errorInfo)
        else:
            self.cutDeep = knifeCutParams.get("cutDeep")
            self.knifeAngleOffset = knifeCutParams.get("knifeAngleOffset")
            self.toolCutSpeed = knifeCutParams.get("toolCutSpped")
            debugInfo = "裁切机工具参数加载: 下刀深度: {},切割速度: {},刀角度补偿: {}".format(
                self.cutDeep, self.toolCutSpeed, self.knifeAngleOffset)
            print(debugInfo)
            self.logger.debug(debugInfo)
            # 角度一开始的默认值是0,如果是0,就先从底层获取角度值
            if self.knifeAngleOffset == 0:
                self.cbjZmc.write_cbj_angle_offset_from_zmc_to_mongo()
            else:
                res, info = self.cbjZmc.set_cbj_angle_offset_from_mongo_to_zmc(self.knifeAngleOffset)
                if res != "ok":
                    errorInfo = info
                    print(errorInfo)
                    self.logger.debug(errorInfo)

    def web_request_get_knife_cut_params(self):
        """
        前端界面请求切割刀参数设置
        :return:
        """
        try:
            res, knifeCutParams = self.db.get_knife_cut_params()
            return [knifeCutParams] if res == "ok" else []
        except Exception as e:
            errorInfo = "in CbjTool.web_request_get_knife_cut_params() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return []

    def web_request_save_knife_cut_params(self, newData):
        """
        前端界面请求保存刀的切割参数
        :param newData: 新的值
        :return:
        """
        try:
            deepMin = 20
            deepSet = float(newData.get("cutDeep"))
            if deepSet < deepMin:
                return "下刀深度最小值为 {} ，设置的下刀深度为 {}, 设定值超过了最小值,设置失败,请重新设定！".format(deepMin, deepSet)
            if deepSet - self.cutDeep > 0.2:
                deepSet = round(float(self.cutDeep) + 0.2, 1)
            newData["cutDeep"] = deepSet
            res, info = self.db.save_knife_cut_params(newData)
            if deepSet != self.cutDeep:
                createTime = sqlHdr.get_create_time()
                data = self.db.get_working_info()[1]
                cutId = str(data.get("cutId", "默认物料号"))
                isOkCutDeep = "Y" if float(deepSet) < 50 else "N"
                data = (cutId, "CUTDEEP", "下刀深度", "mm", self.cutDeep, deepSet,
                        isOkCutDeep, createTime)
                sqlHdr.pc_data_manual_insert_data(data)
            self.reload_knfie_cut_params()
            return "ok" if res == "ok" else info
        except Exception as e:
            errorInfo = "in CbjTool.web_request_save_knife_cut_params() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return errorInfo

    def web_request_open_get_pos(self):
        """
        前端界面点击了坐标反馈的按钮,这个时候要实时发送裁切机的坐标到前端
        :return:
        """
        # 首先是创建线程.
        if not self.sendCbjPosFlag:
            self.sendCbjPosFlag = True
            self.getCbjPosThread = threading.Thread(target=self.send_cbj_pos_to_web)
            self.getCbjPosThread.setDaemon(True)
            self.getCbjPosThread.start()
            return "ok"
        else:
            return "裁切机坐标反馈已开启,打开失败"

    def send_cbj_pos_to_web(self):
        i = 0
        while self.sendCbjPosFlag:
            connected = self.cbjZmc.check_connect()
            if connected:
                res, value = self.cbjZmc.get_axis_postion(4)
                value = ["%.3f" % x for x in value]
                if res != 0:
                    msgValue = {
                        "val": "updateCbjPosState",
                        "cbjPosList": [i, i + 1, i + 2, i + 3]
                    }
                else:
                    msgValue = {
                        "val": "updateCbjPosState",
                        "cbjPosList": value
                    }
            else:
                msgValue = {
                    "val": "updateCbjPosState",
                    "cbjPosList": [i, i + 1, i + 2, i + 3]
                }
            send_cbj_zmc_tool_state_to_ui(msgValue)
            i += 1
            gevent.sleep(0.5)

    def web_request_close_get_pos(self):
        """
        前端界面点击了关闭坐标反馈,将线程终结掉
        :return:
        """
        try:
            if self.getCbjPosThread.is_alive():
                stop_thread(self.getCbjPosThread)
                self.sendCbjPosFlag = False
            return "ok"
        except Exception as e:
            errorInfo = "in CbjTool.web_request_close_get_pos() error: {}".format(str(e))
            print(errorInfo)
            self.logger.debug(errorInfo)
            return errorInfo

    def web_request_cbj_rs_stop(self):
        """
        前端控制器工具界面,点击手动急停按钮
        :return:
        """
        connected = self.cbjZmc.check_connect()
        if connected:
            ret = self.cbjZmc.cbj_zmc_rs_stop()
            return "ok" if ret == 0 else ret
        else:
            return "停止失败,设备没有连接."

    def web_request_cbj_reset(self):
        """
        前端控制器工具界面,点击了手动复位按钮
        :return:
        """
        connected = self.cbjZmc.check_connect()
        if connected:
            ret = self.cbjZmc.cbj_zmc_reset()
            return "ok" if ret == 0 else ret
        else:
            return "复位失败,设备没有连接."

    def web_request_save_point_coord(self, posData):
        """
        前端界面点击了保存标定点的信息
        :param posData: 标定的点的信息,包括几号点以及x坐标和y坐标
        :return:
        """
        posNumber = posData[0]
        posValue = [float(posData[1]), float(posData[2])]
        newData = {
            "point_{}".format(posNumber): posValue,
        }
        res, info = self.db.save_trans_mtx_data(newData)
        return "ok" if res == "ok" else info

    def web_request_axis_abs_move(self, moveInfo):
        """
        前端界面请求绝对移动某一个轴
        :param moveInfo: 移动的信息,[轴号,移动距离]
        :return:
        """
        axisNumber, moveDis = moveInfo
        if axisNumber == "X":
            self.cbjZmc.move_abs_x(float(moveDis))
        elif axisNumber == "Y":
            self.cbjZmc.move_abs_y(float(moveDis))
        elif axisNumber == "Z":
            self.cbjZmc.move_abs_z(float(moveDis))
        elif axisNumber == "W":
            self.cbjZmc.move_abs_w(float(moveDis))

    def web_request_axis_rel_move(self, moveInfo):
        """
        前端界面请求绝对移动某一个轴
        :param moveInfo: 移动的信息,[轴号,移动距离]
        :return:
        """
        axisNumber, moveDis = moveInfo
        if axisNumber == "X":
            self.cbjZmc.move_x(float(moveDis))
        elif axisNumber == "Y":
            self.cbjZmc.move_y(float(moveDis))
        elif axisNumber == "Z":
            self.cbjZmc.move_z(float(moveDis))
        elif axisNumber == "W":
            self.cbjZmc.move_w(float(moveDis))

    def web_request_cut_one_line(self, pointList):
        """
        前端界面请求切直线,普通的不带台面补偿的切直线
        :param pointList: 点的坐标列表[x1,y1,x2,y2]
        :return:
        """
        x1, y1, x2, y2 = pointList
        p1 = (float(x1), float(y1))
        p2 = (float(x2), float(y2))
        self.cbjZmc.cut_one_line_without_capfile(p1, p2, self.cutDeep)

    def web_request_cut_rect(self, pointList):
        """
        前端界面请求切矩形,不带台面补偿的
        :param pointList: 点的坐标列表[x1,y1,x2,y2]
        :return:
        """
        x1, y1, x2, y2 = pointList
        x1 = float(x1)
        y1 = float(y1)
        x2 = float(x2)
        y2 = float(y2)
        self.cbjZmc.cut_one_line_without_capfile((x1, y1), (x1, y2), self.cutDeep)
        self.cbjZmc.cut_one_line_without_capfile((x1, y2), (x2, y2), self.cutDeep)
        self.cbjZmc.cut_one_line_without_capfile((x2, y2), (x2, y1), self.cutDeep)
        self.cbjZmc.cut_one_line_without_capfile((x2, y1), (x1, y1), self.cutDeep)

    def web_request_cut_one_line_with_capfile(self, pointList):
        """
        前端界面点击了带台面补偿的切直线
        :param pointList  点的坐标列表[x1,y1,x2,y2]
        :return:
        """
        pointList = [float(x) for x in pointList]
        x1, y1, x2, y2 = pointList
        lineList = []
        line1 = [(x1, y1), (x2, y2)]
        lineList.append(line1)
        speedList = [self.toolCutSpeed]
        res, info = self.cbjZmc.set_lines_to_cbj_with_capfile(lineList, speedList, self.cutDeep)
        if res == "ok":
            self.logger.debug("切线: {}条 下发成功".format(len(lineList)))
            self.cbjZmc.set_modbus_bit(14, 1)  # 告诉裁切机,切线发送完毕
        else:
            self.logger.debug("切线: {} 下发失败: {}".format(lineList, info))

    def web_request_cut_rect_with_capfile(self, pointList):
        """
        前端界面上点击了带台面补偿的切矩形
        :param pointList:
        :return:
        """
        pointList = [float(x) for x in pointList]
        x1, y1, x2, y2 = pointList
        lineList = []
        line1 = [(x1, y1), (x1, y2)]
        lineList.append(line1)
        line2 = [(x1, y2), (x2, y2)]
        lineList.append(line2)
        line3 = [(x2, y2), (x2, y1)]
        lineList.append(line3)
        line4 = [(x2, y1), (x1, y1)]
        lineList.append(line4)
        speedList = [self.toolCutSpeed, self.toolCutSpeed, self.toolCutSpeed, self.toolCutSpeed]

        res, info = self.cbjZmc.set_lines_to_cbj_with_capfile(lineList, speedList, self.cutDeep)
        if res == "ok":
            self.logger.debug("切线: {}条 下发成功".format(len(lineList)))
            self.cbjZmc.set_modbus_bit(14, 1)  # 告诉裁切机,切线发送完毕
        else:
            self.logger.debug("切线: {}条 下发失败: {}".format(len(lineList), info))

    def web_request_save_knife_offset(self, webData):
        """
        前端界面请求保存刀的偏移值
        :param webData:前端传送过来的列表,里面存放的是偏移值.
        :return:
        """
        offsetX, offsetY = webData
        if offsetX == "" or offsetY == "":
            return "保存失败,填入的值不能是空"
        offsetX = float(offsetX)
        offsetY = float(offsetY)
        newData = {
            "offsetX": offsetX,
            "offsetY": offsetY
        }
        res, info = self.db.save_trans_mtx_data(newData)
        return "ok" if res == "ok" else info

    def web_request_open_output(self, outputName):
        """
        前端界面点击了打开某个输出口
        :param outputName: 输出口的名字
        :return:
        """
        outportVal = 1
        if outputName == "真空吸附":
            outputPos = 8
        elif outputName == "刀片转动":
            outputPos = 9
        elif outputName == "压杆下压":
            outputPos = 10
        elif outputName == "真空破坏":
            outputPos = 1
        elif outputName == "电机报警清除":
            outputPos = 0
        else:
            return "error,传入的输出口的值无效"

        ret = self.cbjZmc.set_output(outputPos, outportVal)
        return "ok" if ret == 0 else ret

    def web_request_close_output(self, outputName):
        """
        界面上点击了关闭某个输出口
        :param outputName: 输出口的名字
        :return:
        """
        outportVal = 0
        if outputName == "真空吸附":
            outputPos = 8
        elif outputName == "刀片转动":
            outputPos = 9
        elif outputName == "压杆下压":
            outputPos = 10
        elif outputName == "真空破坏":
            outputPos = 1
        elif outputName == "电机报警清除":
            outputPos = 0
        else:
            return "error,传入的输出口的值无效"

        ret = self.cbjZmc.set_output(outputPos, outportVal)
        return "ok" if ret == 0 else ret

    def web_request_cut_cross_test(self, crossCenter):
        """
        根据十字中心切割十字
        :param crossCenter: 十字中心点坐标
        :return:
        """
        centerX, centerY = crossCenter
        if centerX == "" or centerY == "":
            return "输入的十字中心坐标不能为空"

        centerX = float(centerX)
        centerY = float(centerY)
        point1 = (centerX - 50, centerY)
        point2 = (centerX + 50, centerY)
        point3 = centerX, centerY - 50
        point4 = centerX, centerY + 50
        self.cbjZmc.cut_one_line_without_capfile(point1, point2, self.cutDeep)
        self.cbjZmc.cut_one_line_without_capfile(point3, point4, self.cutDeep)
        return "ok"

    def web_request_drag_test(self, dragDis):
        """
        前端界面点击拖拽测试的按钮
        :param dragDis: 拖拽的距离.
        :return:
        """
        if dragDis == "":
            return "输入的拖拽距离不能是空"
        self.cbjZmc.set_output(10, 1)
        gevent.sleep(0.5)
        self.cbjZmc.move_x(float(dragDis))
        return "ok"

    def web_request_down_knife(self):
        """
        界面上点击了下刀,先从数据库获取当前深度
        :return:
        """
        res, knifeCutParams = self.db.get_knife_cut_params()
        if res != "ok":
            errorInfo = knifeCutParams
            print(errorInfo)
            self.logger.debug(errorInfo)
            return errorInfo
        else:
            self.cutDeep = knifeCutParams.get("cutDeep")
            if self.cutDeep is None:
                return "数据库中无数据"
            self.cbjZmc.move_abs_z(self.cutDeep)
            return "ok"

    def web_request_up_knife(self):
        """
        界面上点击了抬刀
        :return:
        """
        self.cbjZmc.move_abs_z(0)
        return "ok"

    def web_request_four_axis_abs_move(self, posList):
        """
        前端界面点击了四轴绝对移动
        :param posList:存放的是四个轴绝对移动的坐标
        :return:
        """
        moveList = [float(x) if x != "" else 0 for x in posList]
        self.cbjZmc.move_abs_four_axis(moveList)
        return "ok"
